#include "serial.h"

#include "DSP2833x_Device.h"
#include "DSP2833x_Sci.h"
#include "DSP2833x_GlobalPrototypes.h"

#include <stdio.h>
#include <assert.h>

#define CONSOLE_REGS &SciaRegs

struct c28x_uart
{
    volatile struct SCI_REGS *sci_regs;
};

static struct c28x_uart console;

//
// SCI_read - Read from the SCI RX buffer
//
static int SCI_read(struct c28x_uart *uart, signed char *buf, unsigned count)
{
    assert(uart != NULL);
    uint16_t readCount = 0;
    uint16_t *bufPtr = (uint16_t*) buf;

    if (count == 0)
    {
        return (0);
    }

    while ((readCount < count) && uart->sci_regs->SCIRXST.bit.RXRDY)
    {
        *bufPtr = uart->sci_regs->SCIRXBUF.all & 0xFF;
        readCount++;
        bufPtr++;
    }

    return (readCount);
}

//
// SCI_write - Write to the SCI TX buffer
//
static int SCI_write(struct c28x_uart *uart, const signed char *buf,
                     unsigned count)
{
    assert(uart != NULL);
    uint16_t writeCount = 0;
    uint16_t *bufPtr = (uint16_t*) buf;

    if (count == 0)
    {
        return (0);
    }

    while (writeCount < count)
    {
        while (uart->sci_regs->SCICTL2.bit.TXRDY != 1)
        {
        }
        uart->sci_regs->SCITXBUF = *bufPtr;
        writeCount++;
        bufPtr++;
    }

    return (writeCount);
}

xComPortHandle xSerialPortInitMinimal(unsigned long ulWantedBaud,
                                      unsigned int uxQueueLength)
{
    InitSciaGpio();
    console.sci_regs = CONSOLE_REGS;

    EALLOW;
    // default config

    // 1 stop bit,  No loopback
    // No parity,8 char bits,
    // async mode, idle-line protocol
    console.sci_regs->SCICCR.all = 0x0007;

    // enable TX, RX, internal SCICLK,
    // Disable RX ERR, SLEEP, TXWAKE
    console.sci_regs->SCICTL1.all = 0x0003;

//    console.sci_regs->SCICTL2.bit.TXINTENA = 1;
//    console.sci_regs->SCICTL2.bit.RXBKINTENA = 1;

    console.sci_regs->SCIHBAUD = 0x0001; // 115200 baud @LSPCLK = 22.5MHz (90 MHz SYSCLK).
    console.sci_regs->SCILBAUD = 0x000E7;

    console.sci_regs->SCICTL1.all = 0x0023; // Relinquish SCI from Reset

    EDIS;
    return &console;
}

void vSerialPutString(xComPortHandle pxPort, const signed char *const pcString,
                      unsigned short usStringLength)
{
    assert(pxPort != NULL);
    struct c28x_uart *uart = (struct c28x_uart*) pxPort;
    SCI_write(uart, pcString, usStringLength);
}

signed portBASE_TYPE xSerialPutChar(xComPortHandle pxPort, signed char cOutChar,
                                    TickType_t xBlockTime)
{
    assert(pxPort != NULL);
    int res;
    struct c28x_uart *uart = (struct c28x_uart*) pxPort;
    res = SCI_write(uart, &cOutChar, 1);
    if (res != 1)
    {
        return -1;
    }
    return res;
}

signed portBASE_TYPE xSerialGetChar(xComPortHandle pxPort,
                                    signed char *pcRxedChar,
                                    TickType_t xBlockTime)
{
    assert(pxPort != NULL);
    int res;
    struct c28x_uart *uart = (struct c28x_uart*) pxPort;
    res = SCI_read(uart, pcRxedChar, 1);
    if (res != 1)
    {
        return -1;
    }
    return res;
}

void vSerialClose(xComPortHandle xPort)
{
}
